/*************************************************************************
	> File Name: oj-224.cpp
	> Author: Wang Bo
	> Mail: 1276106221@qq.com
	> Created Time: 2021年01月19日 星期二 15时40分40秒
 ************************************************************************/
#include <cstdio>
using namespace std;
#define MAX_N 100000
struct {
    long long sum, p, m;
} tree[(MAX_N << 2) + 5];
int arr[MAX_N + 5];
//懒标记先乘再加
int n, m, p;

void update(int ind) {
    tree[ind].sum = tree[ind << 1].sum + tree[ind << 1 | 1].sum;
    tree[ind].sum %= p;
}

void build_tree(int ind, int l, int r) {
    tree[ind].m = 1; tree[ind].p = 0;
    if (l == r) {
        tree[ind].sum = arr[l];
        return ;
    }
    int mid = (l + r) >> 1;
    build_tree(ind << 1, l, mid);
    build_tree(ind << 1 | 1, mid + 1, r);
    update(ind);
    return ;
}

void mul_tag(int ind, int x) {
    tree[ind].sum *= x;
    tree[ind].sum %= p;
    tree[ind].m *= x;
    tree[ind].m %= p;
    tree[ind].p *= x;
    tree[ind].p %= p;
    return ;
}

void add_tag(int ind, int x, int n) {
    tree[ind].sum += x * n;
    tree[ind].p += x;
    tree[ind].sum %= p;
    tree[ind].p %= p;
    return ;
}

//标记下沉时，乘法懒标记先下来，加法懒标记随后再下来
void down(int ind, int l, int r) {
    if (tree[ind].m - 1 || tree[ind].p) {
        int a = tree[ind].m, b = tree[ind].p;
        int mid = (l + r) >> 1;
        mul_tag(ind << 1, a);
        mul_tag(ind << 1 | 1, a);
        add_tag(ind << 1, b, mid - l + 1);
        add_tag(ind << 1 | 1, b, r - mid);
        tree[ind].m = 1;
        tree[ind].p = 0;
    }
}

void modify(int ind, int flag, int x, int y, int val, int l, int r) {
    if (x <= l && r <= y) {
        if (flag == 0) {
            mul_tag(ind, val);
        } else {
            add_tag(ind, val, r - l + 1);
        }
        return ;
    }
    down(ind, l, r);
    int mid = (l + r) >> 1;
    if (mid >= x)
        modify(ind << 1, flag, x, y, val, l, mid);
    if (mid < y)
        modify(ind << 1 | 1, flag, x, y, val, mid + 1, r);
    update(ind);
    return ;
}

long long query(int ind, int x, int y, int l, int r) {
    if (x <= l && r <= y) return tree[ind].sum;
    long long ans = 0;
    int mid = (l + r) >> 1;
    down(ind, l, r);
    if (mid >= x) ans += query(ind << 1, x, y, l, mid);
    if (mid < y) ans += query(ind << 1 | 1, x, y, mid + 1, r);
    ans %= p;
    update(ind);
    return ans;
}

int main() {
    int op, x, y, k;
    scanf("%d%d%d", &n, &m, &p);
    for (int i = 1; i <= n; ++i) {
        scanf("%d", arr + i);
    }
    build_tree(1, 1, n);
    for (int i = 0; i < m; ++i) {
        scanf("%d%d%d", &op, &x, &y);
        switch (op) {
            case 1:
            case 2:
            scanf("%d", &k);
            modify(1, op - 1, x, y, k, 1, n);
            break;
            case 3:
            printf("%lld\n",query(1, x, y, 1, n));
            break;
        }
    }
    return 0;
}
